using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Threading;
using InfiniTec;
using InfiniTec.Collections.Generic;

namespace CalendarSubscriptionApp
{
	public sealed class CalendarSubscriptionViewModel : INotifyPropertyChanged
	{
		private static readonly SynchronizationContext _SynchronizationContext = SynchronizationContext.Current ??
		                                                                         new SynchronizationContext();
		private readonly ObservableCollection<AppointmentViewModel> _Appointments = new ObservableCollection<AppointmentViewModel>();
		private readonly CalendarSubscription _Model;
		private readonly SubscriptionManagerViewModel _SubscriptionManager;

		private string _Error;
		private CalendarSubscriptionStatus _Status;

		public string MailboxId
		{
			get { return _Model.MailboxId; }
		}

		public CalendarSubscription Model
		{
			get { return _Model; }
		}

		public CalendarSubscriptionViewModel(CalendarSubscription calendarSubscription, SubscriptionManagerViewModel subscriptionManager, CalendarSubscriptionStatus status)
		{
			if (calendarSubscription == null) throw new ArgumentNullException("calendarSubscription");
			if (subscriptionManager == null) throw new ArgumentNullException("subscriptionManager");
			_Model = calendarSubscription;
			_SubscriptionManager = subscriptionManager;
			_Model.AppointmentAdded += CalendarSubscriptionOnAppointmentAdded;
			_Model.AppointmentRemoved += CalendarSubscriptionOnAppointmentRemoved;
			Status = status;

			Appointments.AddRange(calendarSubscription.Appointments);
		}

		public void CancelSubscription()
		{
			try
			{
				_SubscriptionManager.RemoveSubscription(this);
				if (Status == CalendarSubscriptionStatus.Ok)
				{
					_Model.CancelSubscription();
				}
			}
			catch (Exception ex)
			{
				ErrorMessage = ex.Message;
				Status = CalendarSubscriptionStatus.Error;
			}
		}

		public void StartAsync()
		{
			ThreadPool.QueueUserWorkItem(state =>
			                             	{
			                             		try
			                             		{
			                             			Status = CalendarSubscriptionStatus.Loading;
			                             			_Model.Start();
			                             			Status = CalendarSubscriptionStatus.Ok;
			                             		}
			                             		catch (Exception ex)
			                             		{
			                             			ErrorMessage = ex.Message;
			                             			Status = CalendarSubscriptionStatus.Error;
			                             		}
			                             	}, null);
		}

		private void CalendarSubscriptionOnAppointmentRemoved(object sender, AppointmentEventArgs e)
		{
			_SynchronizationContext.Send(state => _Appointments.Remove(e.Appointment), null);
		}

		private void CalendarSubscriptionOnAppointmentAdded(object sender, AppointmentEventArgs e)
		{
			_SynchronizationContext.Send(state => _Appointments.Add(e.Appointment), null);
		}

		public ObservableCollection<AppointmentViewModel> Appointments
		{
			get { return _Appointments; }
		}

		public CalendarSubscriptionStatus Status
		{
			get { return _Status; }
			set
			{
				if (_Status == value) return;
				_Status = value;
				PropertyChanged.Raise(this, "Status");
			}
		}

		public string ErrorMessage
		{
			get { return _Error; }
			set
			{
				if (_Error == value) return;
				_Error = value;
				PropertyChanged.Raise(this, "ErrorMessage");
			}
		}

		public event PropertyChangedEventHandler PropertyChanged;
	}
}